package mysql

import (
	"beergo/lib/tool"
	"encoding/json"
	"github.com/beego/beego/v2/client/orm"
	"github.com/beego/beego/v2/core/config"
	_ "github.com/beego/beego/v2/core/config/json"
	"github.com/beego/beego/v2/server/web"
	"github.com/beego/beego/v2/server/web/context"
	"strings"
)

type QueryBuilder struct {
	EntityName string                 `json:"_en"`      //数据库实体名称
	Search     string                 `json:"_search"`  //模糊搜索
	Conditions map[string]interface{} `json:"_where"`   //查询条件
	Excludes   map[string]interface{} `json:"_nowhere"` //排除条件
	Order      []string               `json:"_order"`   //排序
	Limit      int                    `json:"limit"`    //每页数量
	Page       int                    `json:"page"`     //页码从1开始
	Total      int64                  `json:"total"`    //总数
	Depth      int                    `json:"_d"`       //层深
	Group      []string               `json:"_g"`       //分组
	Fields     []string               `json:"_f"`       //所需字段
	NoFields   []string               `json:"_nf"`      //排除字段，减少数据库压力
	IsTree     bool                   `json:"_tree"`    //是否要求树形结构
	//IsLoadRelation bool                   `json:"_isrel"`   //关联数据的获取
	Relation []string        `json:"_rel"` //关联数据的获取
	Config   config.Configer //通过配置文件获取的数据
}

func (this *QueryBuilder) FeedBack() map[string]interface{} {
	var data = make(map[string]interface{})
	data["page"] = this.Page
	data["total"] = this.Total
	data["limit"] = this.Limit
	return data
}
func (this *QueryBuilder) GetFilter() map[string]interface{} {
	conditions := tool.StringKeyMap{}
	for k, item := range this.Conditions {
		if item != "" {
			if strings.HasSuffix(k, "__like") {
				k = strings.ReplaceAll(k, "__like", "__icontains")
			}
			if strings.HasSuffix(k, "__sw") {
				k = strings.ReplaceAll(k, "__sw", "__startswith")
			}
			if strings.HasSuffix(k, "__ew") {
				k = strings.ReplaceAll(k, "__ew", "__endswith")
			}
			if strings.HasSuffix(k, "__eq") {
				k = strings.ReplaceAll(k, "__eq", "__iexact")
			}
			conditions[k] = item
		}
	}
	return conditions
}

func (this *QueryBuilder) SetId(id int) *QueryBuilder {
	tool.JsonLog("this")
	tool.JsonLog(this)
	if this.Conditions == nil {
		this.Conditions = make(map[string]interface{})
	}
	this.Conditions["id"] = id
	return this
}

func (this *QueryBuilder) AddCondition(key string, v interface{}) *QueryBuilder {
	if this.Conditions == nil {
		this.Conditions = make(map[string]interface{})
	}
	this.Conditions[key] = v
	return this
}

func (this *QueryBuilder) GetWhere() map[string]interface{} {
	return this.GetFilter()
}
func (this *QueryBuilder) GetExclude() map[string]interface{} {
	excludes := tool.StringKeyMap{}
	for k, item := range this.Excludes {
		if item != "" {
			if strings.HasSuffix(k, "__like") {
				k = strings.ReplaceAll(k, "__like", "__icontains")
			}
			if strings.HasSuffix(k, "__sw") {
				k = strings.ReplaceAll(k, "__sw", "__startswith")
			}
			if strings.HasSuffix(k, "__ew") {
				k = strings.ReplaceAll(k, "__ew", "__endswith")
			}
			if strings.HasSuffix(k, "__eq") {
				k = strings.ReplaceAll(k, "__eq", "__iexact")
			}
			excludes[k] = item
		}
	}
	return excludes
}

func (this *QueryBuilder) GetNoWhere() map[string]interface{} {
	return this.GetFilter()
}

func (this *QueryBuilder) GetOrder() []string { return this.Order }

func (this *QueryBuilder) GetOrderOne() string {
	if len(this.Order) == 0 {
		return ""
	} else {
		return this.Order[0]
	}
}
func (this *QueryBuilder) GetOrderString() string {
	if this == nil || this.Order == nil || len(this.Order) == 0 {
		return ""
	}
	var strs []string
	strs = this.Order
	str := strings.Join(strs, " ")
	return str
}

func (this *QueryBuilder) GetLimit() int { return this.Limit }

func (this *QueryBuilder) GetOffset() int {
	offset := this.Page*this.Limit - this.Limit
	if offset < 0 {
		offset = 0
	}
	return offset
}

func (this *QueryBuilder) GetFields() []string {
	//处理各项数据，得到最终的筛选参数
	return this.Fields
}

func (this *QueryBuilder) GetFieldString() string {
	//处理各项数据，得到最终的筛选参数
	return strings.Join(this.Fields, " ")
}

func (this *QueryBuilder) GetNoFields() []string {
	return this.NoFields
}

func (this *QueryBuilder) GetGroup() string {
	if len(this.Group) == 0 {
		return "default"
	}
	groupString := ""
	for _, group := range this.Group {
		groupString = groupString + " " + group
	}
	return groupString[1:]
}

func (this *QueryBuilder) GetDepth() int {
	if this.Depth == 0 {
		return 1
	}
	return this.Depth
}

func (this *QueryBuilder) Get() []interface{} {
	re := []interface{}{this.Conditions, this.Order, this.Limit, this.Page, this.Total}
	return re
}

func (this *QueryBuilder) ToString() string { buf, _ := json.Marshal(this); return string(buf) }

func (this *QueryBuilder) CreateOrderFromJsonString(orderJson string) []string {
	data := strings.Fields(orderJson)
	order := []string{}
	for _, datum := range data {
		if datum != "" {
			order = append(order, datum)
		}
	}
	return order
}
func (this *QueryBuilder) CreateFilterFromJsonString(orderJson string) map[string]interface{} {
	data := [][]string{}
	json.Unmarshal([]byte(orderJson), &data)
	where := map[string]interface{}{}
	for _, datum := range data {
		item := datum
		if len(item) != 3 {
			continue
		}
		if len(item[0]) == 0 {
			continue
		}
		where[item[0]+"__"+item[1]] = item[2]
	}
	return where
}

func (this *QueryBuilder) Select(data interface{}) error {
	ormer := orm.NewOrm()
	o := ormer.QueryTable(this.EntityName)

	for key, item := range this.GetFilter() {
		o = o.Filter(key, item)
	}
	o = o.OrderBy(this.GetOrder()...)
	this.MakeFields()
	_, err := o.Limit(this.GetLimit()).
		Offset(this.GetOffset()).
		All(&data, this.GetFields()...)
	if len(this.Relation) > 0 {
		for _, f := range this.Relation {
			for _, row := range data.([]interface{}) {
				ormer.LoadRelated(&row, f)
			}
		}
	}
	return err
}
func (this *QueryBuilder) LoadConfig() {
	entityName := this.EntityName
	root := web.AppConfig.DefaultString("Root", "")
	filePath := root + "/models/dict/groups/" + tool.Ucfirst(entityName) + "Config.json"
	cfg, err := config.NewConfig("json", filePath)
	this.Config = cfg
	if err != nil {
		println("NewConfig.Error")
	}
}

func (this *QueryBuilder) SetConfig(cfg config.Configer) *QueryBuilder {
	this.Config = cfg
	return this
}

func (this *QueryBuilder) MakeFields() {
	tmpFields := make([]string, 0)
	if len(this.Group) == 0 {
		configFieldsStr := this.Config.DefaultString("fields::default", "")
		configFields := strings.Fields(configFieldsStr)
		for _, field := range configFields {
			find := false
			for _, noField := range this.NoFields {
				if field == noField {
					find = true
				}
			}
			if find {
				continue
			} else {
				tmpFields = append(tmpFields, field)
			}
		}
	} else {
		for _, group := range this.Group {
			configFieldsStr := this.Config.DefaultString("fields::"+group, "")
			configFields := strings.Fields(configFieldsStr)
			for _, field := range configFields {
				find := false
				for _, noField := range this.NoFields {
					if field == noField {
						find = true
					}
				}
				if find {
					continue
				} else {
					tmpFields = append(tmpFields, field)
				}
			}
		}
	}

	if this.Fields != nil {
		for _, toAdd := range this.Fields {
			tmpFields = append(tmpFields, toAdd)
		}
	}
	this.Fields = tmpFields
	this.MakeRelations()
}
func (this *QueryBuilder) MakeRelations() {
	tmpFields := make([]string, 0)
	if len(this.Group) == 0 {
		configFieldsStr := this.Config.DefaultString("relations::default", "")
		configFields := strings.Fields(configFieldsStr)
		for _, field := range configFields {
			find := false
			for _, noField := range this.NoFields {
				if field == noField {
					find = true
				}
			}
			if find {
				continue
			} else {
				tmpFields = append(tmpFields, field)
			}
		}
	} else {
		for _, group := range this.Group {
			configFieldsStr := this.Config.DefaultString("relations::"+group, "")
			configFields := strings.Fields(configFieldsStr)
			for _, field := range configFields {
				find := false
				for _, noField := range this.NoFields {
					if field == noField {
						find = true
					}
				}
				if find {
					continue
				} else {
					tmpFields = append(tmpFields, field)
				}
			}
		}
	}
	this.Relation = tmpFields
}

func (this *QueryBuilder) MakeScans() string {
	tmpFields := make([]string, 0)
	if len(this.Group) == 0 {
		configFieldsStr := this.Config.DefaultString("scan::default", "")
		configFields := strings.Fields(configFieldsStr)
		for _, field := range configFields {
			find := false
			for _, noField := range this.NoFields {
				if field == noField {
					find = true
				}
			}
			if find {
				continue
			} else {
				tmpFields = append(tmpFields, field)
			}
		}
	} else {
		for _, group := range this.Group {
			configFieldsStr := this.Config.DefaultString("scan::"+group, "")
			configFields := strings.Fields(configFieldsStr)
			for _, field := range configFields {
				find := false
				for _, noField := range this.NoFields {
					if field == noField {
						find = true
					}
				}
				if find {
					continue
				} else {
					tmpFields = append(tmpFields, field)
				}
			}
		}
	}
	if this.Fields != nil {
		for _, toAdd := range this.Fields {
			tmpFields = append(tmpFields, toAdd)
		}
	}
	return strings.Join(tmpFields, " ")
}

func (this *QueryBuilder) SetEntityName(name string) *QueryBuilder {
	this.EntityName = name
	return this
}

func (this *QueryBuilder) CreateFromRequest(ctx *context.Context) *QueryBuilder {
	model := new(QueryBuilder)
	err := json.Unmarshal(ctx.Input.RequestBody, &model)
	if err != nil {
		tool.JsonLog(err.Error())
	}
	return model
}
